import { PostHeaderType } from '../types/data.enum'
import { Snail } from './core'
import _ from 'lodash'
import { serialize } from 'object-to-formdata'
import qs from 'qs'
import { IRequestConfig } from '../types/data.interface'

/**
 * 处理请求地址
 * @param snail aop 容器
 * @param className 类名
 * @param funName 方法名
 * @param url 传入url
 * @returns 返回请求地址 
 */
export const handleRequestUrl = (snail: Snail, className: string, funName: string, url: string): string =>{

    if(/^(http:\/\/|https:\/\/)/.test(url)) {
        return url
    }

    const configMap = snail.getConfig(className) || new Map()
    const tmp = configMap.get(funName)
    if(tmp && tmp['snail_base_url']) {
        return `${tmp['snail_base_url']}${url}`
    }

    if(snail.getBaseUrl(className)) {
        return snail.getBaseUrl(className)
    }

    return url
}
/**处理params参数 */
export const handlerGetParams = (url: string, data: { [key: string]: string}): string => {
    return url.replace(/\{\{(.*?)\}\}/g, (word)=> {
        const key:string = word.substring(2, word.length  - 2)
        return data[key] ? decodeURIComponent(data[key]) : 'undefine'
    })
}
/**
 * 设置请求配置
 * @param snail 
 * @param classKey 
 * @param propertyKey 
 * @param data 
 */
export const handlerRequestSetConfig = (snail: Snail, classKey: string, propertyKey: string, data: IRequestConfig) =>{
    const key = classKey

    const configMap = snail.getConfig(key) || new Map()
    const tmp = configMap.get(propertyKey) ||  {}

    configMap.set(propertyKey, _.merge(tmp, data))

    snail.setConfig(key, configMap)
}

export const handlerPostRequestSetConfig = (snail: Snail, classKey: string, propertyKey: string, url: string,  type: PostHeaderType) =>{
    handlerRequestSetConfig(snail, classKey, propertyKey, {
        url: url,
        method: 'post',
        headers: {
            'Content-Type': type
        }
    })
}
export const handlerGetRequestSetConfig = (snail: Snail, classKey: string, propertyKey: string, url: string) =>{
    handlerRequestSetConfig(snail, classKey, propertyKey, {
        url: url,
        method: 'get',
    })
}



/**
 * 重组请求方法
 * @param snail 
 * @param classKey 
 * @param propertyKey 
 * @param descriptor 
 */
export const handlerGenRequestFun = (snail: Snail, classKey: string, propertyKey: string, descriptor: PropertyDescriptor,  type?: PostHeaderType) => {
    const  oValue =  descriptor.value

    descriptor.value = function () {
        const allConfig = snail!.getConfig(classKey)
        const config =  _.cloneDeep(allConfig!.get(propertyKey))
        const oData = arguments
        const requestUrl = handleRequestUrl(snail, classKey, propertyKey, handlerGetParams(config?.url||'', oData[0] || {}))
        const requestInstance  = snail.getProvider(classKey)
        if(!requestInstance) {
            throw new Error('请提供请求上下文')
        }

        config!.url = requestUrl
        
        if(type) {
            config!.data = oData[0]
            config!.transformRequest = [transformRequestFun()[type]]
        } else {
            config!.params = oData[0]
        }

        /**利用Promise 链式调用 */
        return Promise.resolve(config || {}).then(requestInstance.request).then((res)=>{
            return Promise.resolve(oValue.apply(this, oData)).then(()=>res)
        })

    }
}

export const transformRequestFun = () => {
    return {
        [PostHeaderType.normal]: function(data: Object) {
            return qs.stringify(data)
        },
        [PostHeaderType.json]: function(data: Object)  {
            return JSON.stringify(data)
        },
        [PostHeaderType.formData]: function(data: Object) {
            return serialize(data, {
                indices: true,
                nullsAsUndefineds: false,
                booleansAsIntegers: false,
                allowEmptyArrays: true,
            })
        }
    }
}

/**
 * 转换blob数据
 */
 export function handleBlobTypeData (data: Blob) {
    return new Promise((resolve, reject)=> {
        let reader = new FileReader();
        reader.readAsText(data, 'utf-8');

        reader.onload = function(e) {
            try {
                data = JSON.parse(reader.result as string);
                resolve(data)
            } catch (error) {
                resolve(data)
            }
        }

        reader.onerror = function(err) {
            reject(data)
        }
    })
}
